#include "StdAfx.h"
#include "MultiThreadedTaskBase.h"

using namespace Adaptive::Foundation;
using namespace Adaptive::Foundation::Threading;

/*--------------------------------------------------------------------------------
 * Constructor / Dispose / Destructor Methods
 *------------------------------------------------------------------------------*/
#pragma region Constructor / Dispose / Destructor Methods

MultiThreadedTaskBase::MultiThreadedTaskBase() : AiObjectBase()
{
	_executionThread = nullptr;
	_executionFlag = false;
	_cancelIndicator = false;
}
MultiThreadedTaskBase::MultiThreadedTaskBase(System::String ^taskName) : AiObjectBase()
{
	_executionThread = nullptr;
	_executionFlag = false;
	_cancelIndicator = false;
	Name = taskName;
}
MultiThreadedTaskBase::~MultiThreadedTaskBase() 
{
	Cancel(true);
	_executionThread = nullptr;
	_executionFlag = false;
	_cancelIndicator = false;
}

bool MultiThreadedTaskBase::IsRunning::get()
{
	return ((_executionThread != nullptr) && (_executionThread->IsAlive));
}
bool MultiThreadedTaskBase::Cancelled::get()
{
	bool returnValue = false;

	Thread::BeginCriticalRegion();
	returnValue = _cancelIndicator;
	Thread::EndCriticalRegion();

	return returnValue;
}

void MultiThreadedTaskBase::BeginExecute()
{
	Thread::BeginCriticalRegion();

	if (_executionThread == nullptr)
	{
		_executionThread = gcnew Thread(gcnew ThreadStart(this, &MultiThreadedTaskBase::ExecuteTaskThread));
		_executionThread->IsBackground = true;
		_executionThread->Priority = ThreadPriority::Normal;
		_executionFlag = true;
		_cancelIndicator = false;
		_executionThread->Start();
		OnTaskStart(EventArgs::Empty);
	}
	Thread::EndCriticalRegion();

}
void MultiThreadedTaskBase::EndExecute()
{
	Thread::BeginCriticalRegion();

	while ((_executionThread != nullptr) && (_executionThread->IsAlive))
		Sleep(100);

	delete(_executionThread);
	_executionThread = nullptr;

	Thread::EndCriticalRegion();
}
void MultiThreadedTaskBase::Cancel(bool waitForOperationToComplete)
{
	if (!Cancelled)
	{
		Thread::BeginCriticalRegion();
		System::Threading::Monitor::TryEnter(this, 10);

		_cancelIndicator = true;
		_executionFlag = false;

		try
		{
			System::Threading::Monitor::Exit(this);
		}
		catch(...)
		{
		}
		Thread::EndCriticalRegion();

		System::Threading::Thread::Sleep(100);

		OnTaskCancelled(EventArgs::Empty);

		if (waitForOperationToComplete)
		{
			TerminateThreadExecution();
			_executionThread = nullptr;
			_executionFlag = false;
		}
	}
	
}

void MultiThreadedTaskBase::OnTaskStart(EventArgs^ e)
{
	TaskStart(this, e);
}
void MultiThreadedTaskBase::OnTaskCompleted(EventArgs^ e)
{
	TaskCompleted(this, e);
}
void MultiThreadedTaskBase::OnTaskFailure(EventArgs^ e)
{
	TaskFailure(this, e);
}
void MultiThreadedTaskBase::OnTaskCancelled(EventArgs^ e)
{
	TaskCancelled(this, e);
}
void MultiThreadedTaskBase::OnTaskException(ExceptionEventArgs^ e)
{
	TaskException(this,e);
}
void MultiThreadedTaskBase::OnProgressUpdate(ProgressEventArgs^ e)
{
	Thread::BeginCriticalRegion();
	ProgressUpdate(this, e);
	Thread::EndCriticalRegion();
}
void MultiThreadedTaskBase::OnSubProgressUpdate(ProgressEventArgs^ e)
{
	Thread::BeginCriticalRegion();
	SubProgressUpdate(this, e);
	Thread::EndCriticalRegion();
}

void MultiThreadedTaskBase::ExecuteTaskThread()
{
	bool isDone = false;

	while ((_executionFlag) && (!_cancelIndicator) && (!isDone))
	{
		try
		{
			isDone = ExecuteSingleTaskAction();
		}
		catch(Exception^ ex)
		{
			OnTaskException(gcnew ExceptionEventArgs(ex));
		}

		try
		{
			isDone |= ExecuteTask();
		}
		catch(Exception^ ex)
		{
			OnTaskException(gcnew ExceptionEventArgs(ex));
		}
	}
	OnTaskCompleted(EventArgs::Empty);
}
void MultiThreadedTaskBase::TerminateThreadExecution()
{
	clock_t start = 0;
	clock_t end = 0;

	start = clock();
	end = clock();

	_executionFlag = false;
	Sleep(10);
	while ((_executionThread != nullptr) && (_executionThread->IsAlive) && (end - start < 30000))
	{
		Sleep(100);
		end = clock();
	}

	if ((_executionThread != nullptr) && (_executionThread->IsAlive))
	{
		try
		{
			_executionThread->Abort();
		}
		catch(...)
		{
		}
	}

	delete(_executionThread);
	_executionThread = nullptr;

}
#pragma endregion
